#include "weatherdatafetcher.h"
#include <QString>
#include <QTimer>
#include <QJsonArray>
#include <QRegularExpression>
#include <QVariantMap>
#include <QUrl>
#include <QFileInfo>

static inline QString normalizeIconUrl(const QString &raw)
{
    if (raw.isEmpty()) return QString();
    // 若为 https 的 rescdn.apihz.cn，把文件名映射到 http 的 cn.apihz.cn 以适配部分运行环境的 https 限制
    if (raw.startsWith(QStringLiteral("https://"))) {
        const QUrl u(raw);
        const QString host = u.host();
        QString fileName = QFileInfo(u.path()).fileName();
        if (!fileName.isEmpty() && host.contains(QStringLiteral("rescdn.apihz.cn"))) {
            // 线上 icon 目录常用 .gif；若返回 .png，优先尝试同名 .gif 以提高命中率
            if (fileName.endsWith(QStringLiteral(".png"), Qt::CaseInsensitive)) {
                fileName.chop(4);
                fileName += QStringLiteral(".gif");
            }
            return QStringLiteral("http://cn.apihz.cn/skin/tianqi/icon/") + fileName;
        }
        return raw;
    }
    // 已是 http 绝对 URL
    if (raw.startsWith(QStringLiteral("http://"))) return raw;
    // APIHZ 常返回形如 "2.gif" 或 "duoyun.png" 的文件名，拼接到站点图标目录
    // 参考文档与线上资源路径（按 http，避免 SSL）
    return QStringLiteral("http://cn.apihz.cn/skin/tianqi/icon/") + raw;
}

// 在 OpenHarmony 的部分运行环境下不支持 HTTPS 协议栈（会报 "Protocol \"https\" is unknown"）
// 这里优先使用 http，确保可用性；目标接口（cn.apihz.cn）支持 http 访问
static inline QString preferredScheme()
{
    return QStringLiteral("http");
}

static inline QString percent(const QString &s)
{
    return QString::fromUtf8(QUrl::toPercentEncoding(s));
}

WeatherDataFetcher::WeatherDataFetcher(QObject *parent)
    : QObject(parent)
    , m_networkManager(new QNetworkAccessManager(this))
    , m_cityName("北京")
    , m_temperature("--")
    , m_weatherCondition("--")
    , m_humidity("--")
    , m_windSpeed("--")
    , m_pressure("--")
    , m_visibility("--")
    , m_loading(false)
    , m_apiHzId("")
    , m_apiHzKey("")
{
    connect(m_networkManager, &QNetworkAccessManager::finished,
            this, &WeatherDataFetcher::onNetworkReplyFinished);
    prepareApiHzCandidates();
}

void WeatherDataFetcher::fetchWeather(const QString &city)
{
    if (city.isEmpty()) {
        qDebug() << "城市名称不能为空";
        emit weatherFetched(false, "城市名称不能为空");
        return;
    }
    if (m_apiHzId.isEmpty() || m_apiHzKey.isEmpty()) {
        qDebug() << "缺少接口凭证 apiHzId/apiHzKey";
        emit weatherFetched(false, "请先设置 apiHzId 与 apiHzKey");
        return;
    }

    setLoading(true);

    // 允许多种输入分隔：空格/逗号/顿号/斜杠/短横线
    QString input = city.trimmed();
    QString separators = "[\\s,，、/|-]";
    QStringList tokens = input.split(QRegularExpression(separators), Qt::SkipEmptyParts);

    auto normalizeName = [](const QString &name) -> QString {
        QString n = name.trimmed();
        static const QStringList suffixes = {QStringLiteral("省"), QStringLiteral("市"),
                                             QStringLiteral("区"), QStringLiteral("县")};
        for (const QString &s : suffixes) {
            if (n.endsWith(s)) {
                n.chop(s.size());
                break;
            }
        }
        return n;
    };

    QString sheng;   // 省份，可为空（若只提供城市）
    QString place;   // 城市/区县
    if (tokens.size() >= 2) {
        sheng = normalizeName(tokens.at(0));
        place = normalizeName(tokens.at(1));
    } else {
        sheng = "";
        place = normalizeName(tokens.first());
    }

    // 记录最近一次请求参数，用于失败重试
    m_lastShengParam = sheng;
    m_lastPlaceParam = place;
    m_apiHzTryIndex = 0;
    issueApiHzRequest();
}

void WeatherDataFetcher::fetchWeatherByLocation(double latitude, double longitude)
{
    setLoading(true);
    QString url = QString("https://api.openweathermap.org/data/2.5/weather?lat=%1&lon=%2&appid=your_api_key&units=metric&lang=zh_cn")
                  .arg(latitude)
                  .arg(longitude);
    
    QNetworkRequest request;
    request.setUrl(QUrl(url));
    QNetworkReply *reply = m_networkManager->get(request);
}

void WeatherDataFetcher::onNetworkReplyFinished(QNetworkReply *reply)
{
    setLoading(false);
    
    if (reply->error() != QNetworkReply::NoError) {
        const QString stage = reply->request().attribute(QNetworkRequest::User).toString();
        const QString err = reply->errorString();
        qDebug() << "网络请求错误:" << err;
        reply->deleteLater();
        // 对 APIHZ 阶段执行候选地址重试
        if (stage == QStringLiteral("apihz") && m_apiHzTryIndex + 1 < m_apiHzBases.size()) {
            m_apiHzTryIndex++;
            qDebug() << "APIHZ 切换候选节点重试, index =" << m_apiHzTryIndex;
            setLoading(true);
            issueApiHzRequest();
            return;
        }
        emit weatherFetched(false, err);
        return;
    }
    
    QByteArray data = reply->readAll();
    reply->deleteLater();
    
    QJsonParseError error;
    QJsonDocument doc = QJsonDocument::fromJson(data, &error);
    
    if (error.error != QJsonParseError::NoError) {
        qDebug() << "JSON 解析错误:" << error.errorString();
        emit weatherFetched(false, "JSON 解析失败");
        return;
    }
    
    QJsonObject json = doc.object();
    qDebug() << "收到天气数据:" << json;

    // 根据请求阶段分派
    const QVariant stageVar = reply->request().attribute(QNetworkRequest::User);
    const QString stage = stageVar.toString();

    if (stage == "apihz") {
        // 若返回不是 200，在 parseApiHzWeather 内会发出失败信号
        // 在失败时尝试候选地址重试
        const int beforeIndex = m_apiHzTryIndex;
        // 先尝试解析
        if (json.contains("code") && json.value("code").toInt() == 200) {
            parseApiHzWeather(json);
            emit weatherFetched(true);
        } else {
            const QString msg = json.contains("msg") ? json.value("msg").toString()
                                                     : QStringLiteral("接口返回错误");
            qDebug() << "APIHZ 返回错误:" << msg;
            if (m_apiHzTryIndex + 1 < m_apiHzBases.size()) {
                m_apiHzTryIndex++;
                qDebug() << "APIHZ 切换候选节点重试, index =" << m_apiHzTryIndex;
                setLoading(true);
                issueApiHzRequest();
            } else {
                emit weatherFetched(false, msg);
            }
        }
        return;
    }

    // weather_common 阶段
    parseWeatherData(json);
    emit weatherFetched(true);
}

void WeatherDataFetcher::parseWeatherData(const QJsonObject &json)
{
    // 优先尝试腾讯天气结构：{ status, message, data: { observe: {...}, forecast_24h: {...} } }
    if (json.contains("data") && json["data"].isObject()) {
        QJsonObject dataObj = json["data"].toObject();

        // 城市名称
        if (dataObj.contains("observe") && dataObj["observe"].isObject()) {
            QJsonObject obs = dataObj["observe"].toObject();
            // 城市字段可能叫 city 或 city_name
            if (obs.contains("city")) setCityName(obs["city"].toString());
            else if (obs.contains("city_name")) setCityName(obs["city_name"].toString());

            // 温度字段可能为 degree 或 temp
            double tempVal = obs.contains("degree") ? obs["degree"].toDouble()
                                                    : obs.contains("temp") ? obs["temp"].toDouble()
                                                                            : qQNaN();
            if (!qIsNaN(tempVal)) setTemperature(QString::number(qRound(tempVal)) + "°C");

            // 天气现象：weather, weather_short, text
            if (obs.contains("weather")) setWeatherCondition(obs["weather"].toString());
            else if (obs.contains("weather_short")) setWeatherCondition(obs["weather_short"].toString());
            else if (obs.contains("text")) setWeatherCondition(obs["text"].toString());

            // 湿度：humidity
            if (obs.contains("humidity")) setHumidity(QString::number(obs["humidity"].toInt()) + "%");

            // 气压：pressure
            if (obs.contains("pressure")) setPressure(QString::number(obs["pressure"].toInt()) + " hPa");

            // 风速：wind_speed 或 wind_speed_float（m/s 或 km/h 不统一，统一显示原值）
            if (obs.contains("wind_speed")) {
                setWindSpeed(QString::number(obs["wind_speed"].toDouble(), 'f', 1));
            } else if (obs.contains("wind_speed_float")) {
                setWindSpeed(QString::number(obs["wind_speed_float"].toDouble(), 'f', 1));
            }
        }

        // 如果还没有城市名，试着从 forecast_24h 的第1天取城市
        if (m_cityName.isEmpty() && dataObj.contains("forecast_24h")) {
            QJsonObject f24 = dataObj["forecast_24h"].toObject();
            if (f24.contains("0") && f24["0"].isObject()) {
                QJsonObject day0 = f24["0"].toObject();
                if (day0.contains("city")) setCityName(day0["city"].toString());
            }
        }
    } else {
        // 兼容之前的 OpenWeather 结构，防止切换期间崩溃
        if (json.contains("name")) setCityName(json["name"].toString());
        if (json.contains("main")) {
            QJsonObject main = json["main"].toObject();
            if (main.contains("temp")) setTemperature(QString::number(qRound(main["temp"].toDouble())) + "°C");
            if (main.contains("humidity")) setHumidity(QString::number(main["humidity"].toInt()) + "%");
            if (main.contains("pressure")) setPressure(QString::number(main["pressure"].toInt()) + " hPa");
        }
        if (json.contains("weather") && json["weather"].isArray()) {
            QJsonArray arr = json["weather"].toArray();
            if (!arr.isEmpty()) {
                QJsonObject w = arr[0].toObject();
                if (w.contains("description")) setWeatherCondition(w["description"].toString());
            }
        }
        if (json.contains("wind")) {
            QJsonObject wind = json["wind"].toObject();
            if (wind.contains("speed"))
                setWindSpeed(QString::number(wind["speed"].toDouble(), 'f', 1));
        }
        if (json.contains("visibility")) {
            int vis = json["visibility"].toInt();
            setVisibility(QString::number(vis / 1000.0, 'f', 1) + " km");
        }
    }
    
    qDebug() << "解析完成 - 城市:" << m_cityName 
             << "温度:" << m_temperature 
             << "天气:" << m_weatherCondition;
}

void WeatherDataFetcher::parseApiHzWeather(const QJsonObject &json)
{
    // 结构参考：https://cloud.tencent.com/developer/article/2537866
    if (!json.contains("code") || json["code"].toInt() != 200) {
        const QString msg = json.contains("msg") ? json["msg"].toString()
                                                 : QStringLiteral("请求失败");
        qDebug() << "APIHZ 返回错误:" << msg;
        return;
    }

    // 城市名优先级：name -> shi -> place
    if (json.contains("name")) setCityName(json["name"].toString());
    else if (json.contains("shi")) setCityName(json["shi"].toString());
    else if (json.contains("place")) setCityName(json["place"].toString());

    // 当前温度优先使用 nowinfo.temperature，其次 wd1
    if (json.contains("nowinfo") && json["nowinfo"].isObject()) {
        QJsonObject now = json["nowinfo"].toObject();
        if (now.contains("temperature")) {
            setTemperature(QString::number(qRound(now["temperature"].toDouble())) + "°C");
        }
        if (now.contains("feelst")) {
            setFeelsLike(QString::number(qRound(now["feelst"].toDouble())) + "°C");
        }
        // 湿度
        if (now.contains("humidity")) {
            QString hum = now["humidity"].isString()
                        ? now["humidity"].toString()
                        : QString::number(qRound(now["humidity"].toDouble())) + "%";
            setHumidity(hum);
        }
        // 气压
        if (now.contains("pressure")) {
            setPressure(QString::number(qRound(now["pressure"].toDouble())) + " hPa");
        }
        // 风
        QString wind;
        if (now.contains("windScale")) wind += now["windScale"].toString();
        if (now.contains("windDirection")) {
            setWindDirectionStr(now["windDirection"].toString());
        }
        if (now.contains("windSpeed")) {
            if (!wind.isEmpty()) wind += " ";
            wind += QString::number(now["windSpeed"].toDouble(), 'f', 1) + " m/s";
        }
        if (now.contains("windScale")) setWindScaleStr(now["windScale"].toString());
        if (!wind.isEmpty()) setWindSpeed(wind);
        if (now.contains("precipitation")) {
            setPrecipitation(QString::number(now["precipitation"].toDouble(), 'f', 1) + " mm");
        }
    } else if (json.contains("wd1")) {
        setTemperature(QString::number(qRound(json["wd1"].toDouble())) + "°C");
    }
    // 合成天气现象
    QString w1 = json.contains("weather1") ? json["weather1"].toString() : QString();
    QString w2 = json.contains("weather2") ? json["weather2"].toString() : QString();
    QString cond = w1;
    if (!w2.isEmpty() && w2 != w1) cond += QStringLiteral("转") + w2;
    if (!cond.isEmpty()) setWeatherCondition(cond);
    if (json.contains("weather1img")) {
        setIcon(normalizeIconUrl(json["weather1img"].toString()));
    }
    if (json.contains("uptime")) {
        setUpdateTime(json["uptime"].toString());
    }
    // 小时预报 hour1
    QVariantList hourList;
    if (json.contains("hour1") && json["hour1"].isArray()) {
        QJsonArray arr = json["hour1"].toArray();
        for (const QJsonValue &v : arr) {
            if (!v.isObject()) continue;
            QJsonObject h = v.toObject();
            QVariantMap m;
            m["time"] = h.value(QStringLiteral("时间")).toString();
            // 兼容不同命名：气温/温度/温度℃，若是数值补上单位
            QString tempStr;
            if (h.contains(QStringLiteral("气温"))) tempStr = h.value(QStringLiteral("气温")).toString();
            else if (h.contains(QStringLiteral("温度"))) tempStr = h.value(QStringLiteral("温度")).toString();
            else if (h.contains(QStringLiteral("温度℃"))) tempStr = h.value(QStringLiteral("温度℃")).toString();
            if (tempStr.isEmpty() && h.value(QStringLiteral("气温")).isDouble()) {
                tempStr = QString::number(qRound(h.value(QStringLiteral("气温")).toDouble())) + QStringLiteral("°C");
            }
            if (!tempStr.contains(QRegularExpression(QStringLiteral("°|℃")))) {
                // 没有单位时追加 °C
                bool okNum = false;
                tempStr.toDouble(&okNum);
                if (okNum) tempStr += QStringLiteral("°C");
            }
            m["temp"] = tempStr;
            m["text"] = h.value(QStringLiteral("天气")).toString();
            m["icon"] = normalizeIconUrl(h.value(QStringLiteral("图标")).toString());
            {
                const QString fx = h.value(QStringLiteral("风向")).toString();
                QString fs = h.value(QStringLiteral("风速")).toString();
                if (fs.isEmpty() && h.value(QStringLiteral("风速")).isDouble())
                    fs = QString::number(h.value(QStringLiteral("风速")).toDouble(), 'f', 1) + QStringLiteral(" m/s");
                m["wind"] = fx.isEmpty() && fs.isEmpty() ? QString() : (fx + QStringLiteral(" ") + fs);
            }
            m["pressure"] = h.value(QStringLiteral("气压")).toString();
            m["humidity"] = h.value(QStringLiteral("湿度")).toString();
            m["precip"] = h.value(QStringLiteral("降水")).toString();
            hourList.push_back(m);
        }
    }
    setHourly(hourList);

    // 其余观测项已在 nowinfo 内处理
    // 无显式可用的能见度字段，保持已有
    qDebug() << "APIHZ 解析完成 - 城市:" << m_cityName
             << "温度:" << m_temperature
             << "天气:" << m_weatherCondition;
}

void WeatherDataFetcher::prepareApiHzCandidates()
{
    m_apiHzBases.clear();
    // 来自文档的集群IP接口（HTTP）
    // https://www.apihz.cn/api/tqtqyb.html
    m_apiHzBases << QStringLiteral("http://101.35.2.25")
                 << QStringLiteral("http://124.222.204.22")
                 << QStringLiteral("http://81.68.149.132")
                 // 域名接口也加入（使用 http，避免 SSL）
                 << QStringLiteral("http://cn.apihz.cn");
}

QString WeatherDataFetcher::buildApiHzUrl(const QString &base, const QString &sheng, const QString &place) const
{
    // GET: /api/tianqi/tqyb.php?id=&key=&sheng=&place=&day=1&hourtype=1
    const QString path = QStringLiteral("/api/tianqi/tqyb.php");
    const QString url = QStringLiteral("%1%2?id=%3&key=%4&sheng=%5&place=%6&day=1&hourtype=1")
                            .arg(base)
                            .arg(path)
                            .arg(percent(m_apiHzId))
                            .arg(percent(m_apiHzKey))
                            .arg(percent(sheng))
                            .arg(percent(place));
    return url;
}

void WeatherDataFetcher::issueApiHzRequest()
{
    if (m_apiHzBases.isEmpty()) {
        prepareApiHzCandidates();
    }
    const int idx = qBound(0, m_apiHzTryIndex, m_apiHzBases.size() - 1);
    const QString base = m_apiHzBases.at(idx);
    const QString url = buildApiHzUrl(base, m_lastShengParam, m_lastPlaceParam);

    qDebug() << "WeatherApp 使用 APIHZ 请求: sheng=" << m_lastShengParam << "place=" << m_lastPlaceParam;
    qDebug() << "APIHZ 节点(" << idx << "):" << base;
    qDebug() << "APIHZ URL:" << url;

    QNetworkRequest req;
    req.setUrl(QUrl(url));
    req.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
    req.setAttribute(QNetworkRequest::User, QVariant("apihz"));
    m_networkManager->get(req);
}
void WeatherDataFetcher::setCityName(const QString &name)
{
    if (m_cityName != name) {
        m_cityName = name;
        emit cityNameChanged();
    }
}

void WeatherDataFetcher::setTemperature(const QString &temp)
{
    if (m_temperature != temp) {
        m_temperature = temp;
        emit temperatureChanged();
    }
}

void WeatherDataFetcher::setWeatherCondition(const QString &condition)
{
    if (m_weatherCondition != condition) {
        m_weatherCondition = condition;
        emit weatherConditionChanged();
    }
}

void WeatherDataFetcher::setHumidity(const QString &hum)
{
    if (m_humidity != hum) {
        m_humidity = hum;
        emit humidityChanged();
    }
}

void WeatherDataFetcher::setWindSpeed(const QString &wind)
{
    if (m_windSpeed != wind) {
        m_windSpeed = wind;
        emit windSpeedChanged();
    }
}

void WeatherDataFetcher::setPressure(const QString &pres)
{
    if (m_pressure != pres) {
        m_pressure = pres;
        emit pressureChanged();
    }
}

void WeatherDataFetcher::setVisibility(const QString &vis)
{
    if (m_visibility != vis) {
        m_visibility = vis;
        emit visibilityChanged();
    }
}

void WeatherDataFetcher::setLoading(bool load)
{
    if (m_loading != load) {
        m_loading = load;
        emit loadingChanged();
    }
}

